home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 418_02 / rasmol2 / render.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-02  |  38.3 KB  |  1,385 lines

  1. /* render.c
  2.  * RasMol2 Molecular Graphics
  3.  * Roger Sayle, February 1994
  4.  * Version 2.3
  5.  */
  6. #include "rasmol.h"
  7.  
  8. #ifdef IBMPC
  9. #include <windows.h>
  10. #include <malloc.h>
  11. #endif
  12. #ifndef sun386
  13. #include <stdlib.h>
  14. #endif
  15.  
  16. #include <stdio.h>
  17. #include <math.h>
  18.  
  19. #define RENDER
  20. #include "graphics.h"
  21. #include "render.h"
  22. #include "molecule.h"
  23. #include "transfor.h"
  24. #include "command.h"
  25. #include "abstree.h"
  26. #include "pixutils.h"
  27.  
  28.  
  29. #define PoolSize        16
  30. #define RootSix         2.4494897427831780
  31. #define OneOverRootSix  0.4082482904638630
  32. #define TwoOverRootSix  0.8164965809277260
  33. #define ApproxZero      1.0E-3
  34. #define INFINITY       200000
  35. #define FUDGEFACTOR    1000
  36.  
  37.  
  38. typedef struct _Item {
  39.                 struct _Item __far *list;
  40.                 Atom  __far *data;
  41.                } Item;
  42.  
  43. typedef struct { Real h,l; } Interval;
  44.  
  45. static Atom __far * __far *YBucket;
  46. static Atom __far * __far *IBuffer;
  47. static int BuckY,ItemX;
  48. static int FBufX,FBufY;
  49. static int DBClear;
  50.  
  51. static Atom __far *SBuffer;
  52. static Atom __far *Exclude;
  53. static Real ShadowI, ShadowJ, ShadowK;
  54. static int  ShadowX, ShadowY, ShadowZ;
  55. static int deltax, deltay, deltaz;
  56. static int xcord, ycord, zcord;
  57. static int xflag, yflag, zflag;
  58. static int xhash, yhash, zhash;
  59. static int RayCount;
  60.  
  61. static Item __far *FreeItem;
  62. static Real VoxRatio,IVoxRatio;
  63. static int VoxelCount,InVoxCount;
  64. static int ProbeCount;
  65. static int VoxelsDone;
  66.  
  67.  
  68. /* Macros for commonly used loops */
  69. #define ForEachAtom  for(chain=Database->clist;chain;chain=chain->cnext) \
  70.                      for(group=chain->glist;group;group=group->gnext)    \
  71.                      for(aptr=group->alist;aptr;aptr=aptr->anext)
  72. #define ForEachBond  for(bptr=Database->blist;bptr;bptr=bptr->bnext)
  73. #define ForEachBack  for(chain=Database->clist;chain;chain=chain->cnext) \
  74.                      for(bptr=chain->blist;bptr;bptr=bptr->bnext)
  75.  
  76.  
  77.  
  78.  
  79. static void FatalRenderError(ptr)
  80.     char *ptr;
  81. {
  82.     char buffer[80];
  83.  
  84.     sprintf(buffer,"Renderer Error: Unable to allocate %s!",ptr);
  85.     RasMolFatalExit(buffer);
  86. }
  87.  
  88.  
  89. int isqrt( val )
  90.     Card val;
  91. {
  92.     register Card side, left;
  93.     register Card temp, result;
  94.     register int i;
  95.  
  96.     result = side = left = 0;
  97.     for( i=0; i<sizeof(Card)*4; i++ )
  98.     {   left = (left<<2) + (val>>30);
  99.         result <<= 1; side <<= 1;
  100.         temp = side | 1;
  101.         val <<= 2;
  102.  
  103.         if( left >= temp )
  104.         {   side = temp+1;
  105.             left -= temp;
  106.             result |= 1;
  107.         }
  108.     }
  109.     return( (int)result );
  110. }
  111.  
  112.  
  113. void ClearBuffers()
  114. {
  115.     register Long __huge *ptr;
  116.     register Long __huge *end;
  117.     register Long fill;
  118.  
  119.     if( !FBClear )
  120.     {   FBClear = True;
  121.  
  122. #ifdef IBMPC
  123.         FBuffer = (Pixel __huge*)GlobalLock(FBufHandle);
  124.         fill = 0;
  125. #else
  126.         fill = Lut[5];
  127. #ifdef EIGHTBIT
  128.         fill |= fill<<8;
  129.         fill |= fill<<16;
  130. #endif
  131. #endif
  132.  
  133.         ptr = (Long __huge*)FBuffer;
  134.         end = (Long __huge*)(FBuffer+(Long)XRange*YRange);
  135.         do { *ptr++=fill; *ptr++=fill;
  136.              *ptr++=fill; *ptr++=fill;
  137.         } while( ptr<end );
  138. #ifdef IBMPC
  139.         GlobalUnlock(FBufHandle);
  140. #endif
  141.     }
  142.  
  143.     if( !DBClear )
  144.     {   DBClear = True;
  145. #ifdef IBMPC
  146.         DBuffer = (short __huge*)GlobalLock(DBufHandle);
  147. #endif
  148.         ptr = (Long __huge*)DBuffer;
  149.         end = (Long __huge*)(DBuffer+(Long)XRange*YRange);
  150.         do { *ptr++=0; *ptr++=0;
  151.              *ptr++=0; *ptr++=0;
  152.         } while( ptr<end );
  153. #ifdef IBMPC
  154.         GlobalUnlock(DBufHandle);
  155. #endif
  156.     }
  157. }
  158.  
  159.  
  160. void ReAllocBuffers()
  161. {
  162.     register Atom __far * __far *iptr;
  163.     register int index,len;
  164.     register Long temp;
  165.  
  166.     temp = (Long)XRange*YRange*sizeof(short)+32;
  167. #ifdef IBMPC
  168.     if( DBufHandle ) GlobalFree(DBufHandle);
  169.     DBufHandle = GlobalAlloc(GMEM_MOVEABLE,temp);
  170.     if( !DBufHandle ) FatalRenderError("depth buffer");
  171. #else
  172.     if( DBuffer ) free( DBuffer );
  173.     DBuffer = (short*)malloc( temp );
  174.     if( !DBuffer ) FatalRenderError("depth buffer");
  175. #endif
  176.     DBClear=False;
  177.  
  178.     if( YBucket && (BuckY<YRange) )
  179.     {   _ffree(YBucket); 
  180.         YBucket=(void __far*)0; 
  181.     }
  182.  
  183.     if( !YBucket )
  184.     {   len = YRange*sizeof(Atom __far*);
  185.         YBucket = (Atom __far* __far*)_fmalloc( len );
  186.         if( !YBucket ) FatalRenderError("Y buckets");
  187.         BuckY = YRange;
  188.     }
  189.  
  190.     if( IBuffer && (ItemX<XRange) )
  191.     {   _ffree(IBuffer); 
  192.         IBuffer=(void __far*)0; 
  193.     }
  194.  
  195.     if( !IBuffer )
  196.     {   len = (XRange+4)*sizeof(Atom __far*);
  197.         IBuffer = (Atom __far* __far*)_fmalloc(len);
  198.         if( !IBuffer ) FatalRenderError("item buffer");
  199.         len = XRange>>2;  iptr = IBuffer;
  200.         for( index=0; index<=len; index++ )
  201.         {   *iptr++ = (void __far*)0;  *iptr++ = (void __far*)0;
  202.             *iptr++ = (void __far*)0;  *iptr++ = (void __far*)0;
  203.         }
  204.         ItemX = XRange;
  205.     }
  206. }
  207.  
  208.  
  209. void ReSizeScreen()
  210. {
  211.     register Real orig;
  212.     register Long temp;
  213.  
  214.     if( Range != ZoomRange )
  215.     {   orig = MaxZoom;
  216.         MaxZoom = 0.236*(WorldSize+1000)/Range;
  217.         ZoomRange = Range;  MaxZoom -= 1.0;
  218.  
  219.         /* Handle Change in MaxZoom */
  220.         if( DialValue[3]>0.0 )
  221.         {   DialValue[3] *= orig/MaxZoom;
  222.             if( DialValue[3]>1.0 )
  223.                 DialValue[3] = 1.0;
  224.         }
  225.     }
  226.  
  227. #ifdef IBMPC
  228.     if( !FBufHandle || (FBufX!=XRange) || (FBufY!=YRange) )
  229.     {   temp = (Long)XRange*YRange*sizeof(Pixel)+16;
  230.         if( FBufHandle ) GlobalFree(FBufHandle);
  231.         FBufHandle = GlobalAlloc(GMEM_MOVEABLE,temp);
  232.         if( !FBufHandle ) FatalRenderError("frame buffer");
  233.  
  234.         BucketFlag = False;
  235.         FBufX=XRange;  FBufY=YRange;  FBClear = False;
  236.         ReAllocBuffers();
  237.         ClearBuffers();
  238.     }
  239. #else /* UNIX */
  240.     if( !FBuffer || (FBufX!=XRange) || (FBufY!=YRange) )
  241.     {   if( !Interactive )
  242.         {   if( FBuffer ) free(FBuffer);
  243.             temp = (Long)XRange*YRange*sizeof(Pixel);
  244.             FBuffer = (Pixel*)malloc( temp+32 );
  245.         } else FBuffer = CreateImage();
  246.         if( !FBuffer ) FatalRenderError("frame buffer");
  247.  
  248.         BucketFlag = False;
  249.         FBufX=XRange;  FBufY=YRange;  FBClear = False;
  250.         ReAllocBuffers();
  251.         ClearBuffers();
  252.     }
  253. #endif
  254. }
  255.  
  256.  
  257. static void DisplayWireFrame()
  258. {
  259.     register Bond __far *bptr;
  260.     register Atom __far *s;
  261.     register Atom __far *d;
  262.     register int sc,dc;
  263.  
  264.     if( UseClipping )
  265.     {   ForEachBond
  266.            if( bptr->flag&WireFlag )
  267.            {   s = bptr->srcatom; d = bptr->dstatom;
  268.                if( !bptr->col ) 
  269.                {   sc = s->col;  dc = d->col;
  270.                } else sc = dc = bptr->col;
  271.                ClipTwinVector(s->x,s->y,s->z,d->x,d->y,d->z,sc,dc);
  272.            } else if( bptr->flag&CylinderFlag )
  273.            {   s = bptr->srcatom; d = bptr->dstatom;
  274.                if( !bptr->col ) 
  275.                {   sc = s->col;  dc = d->col;
  276.                } else sc = dc = bptr->col;
  277.  
  278.                if( bptr->irad>0 )
  279.                {  ClipCylinder(s->x,s->y,s->z,sc,d->x,d->y,d->z,dc,bptr->irad);
  280.                } else ClipTwinLine(s->x,s->y,s->z,d->x,d->y,d->z,sc,dc);
  281.            }
  282.     } else
  283.         ForEachBond
  284.            if( bptr->flag&WireFlag )
  285.            {   s = bptr->srcatom; d = bptr->dstatom;
  286.                if( !bptr->col ) 
  287.                {   sc = s->col;  dc = d->col;
  288.                } else sc = dc = bptr->col;
  289.                DrawTwinVector(s->x,s->y,s->z,d->x,d->y,d->z,sc,dc);
  290.            } else if( bptr->flag&CylinderFlag )
  291.            {   s = bptr->srcatom; d = bptr->dstatom;
  292.                if( !bptr->col ) 
  293.                {   sc = s->col;  dc = d->col;
  294.                } else sc = dc = bptr->col;
  295.  
  296.                if( bptr->irad>0 )
  297.                {  DrawCylinder(s->x,s->y,s->z,sc,d->x,d->y,d->z,dc,bptr->irad);
  298.                } else DrawTwinLine(s->x,s->y,s->z,d->x,d->y,d->z,sc,dc);
  299.            }
  300. }
  301.  
  302.  
  303. static void DisplayBackBone()
  304. {
  305.     register Chain __far *chain;
  306.     register Bond __far *bptr;
  307.     register Atom __far *s;
  308.     register Atom __far *d;
  309.     register int sc,dc;
  310.  
  311.     ForEachBack
  312.        if( bptr->flag&DrawBondFlag )
  313.        {   s = bptr->srcatom; d = bptr->dstatom;
  314.            if( !bptr->col ) 
  315.            {   sc = s->col;  dc = d->col;
  316.            } else sc = dc = bptr->col;
  317.  
  318.            if( bptr->flag&CylinderFlag )
  319.            {   if( bptr->irad>0 )
  320.                { ClipCylinder(s->x,s->y,s->z,sc,d->x,d->y,d->z,dc,bptr->irad);
  321.                } else ClipTwinLine(s->x,s->y,s->z,d->x,d->y,d->z,sc,dc);
  322.            } else ClipTwinVector(s->x,s->y,s->z,d->x,d->y,d->z,sc,dc);
  323.        }
  324. }
  325.  
  326.  
  327. static void PrepareYBucket()
  328. {
  329.     register Atom __far * __far *temp;
  330.     register Chain __far *chain;
  331.     register Group __far *group;
  332.     register Atom __far *aptr;
  333.     register int scan;
  334.     register int rad;
  335.  
  336.     temp = YBucket;
  337.     for( scan=0; scan<BuckY; scan++ )
  338.         *temp++ = (void __far*)0;
  339.  
  340.     if( UseClipping )
  341.     {   ForEachAtom
  342.             if( aptr->flag&SphereFlag )
  343.             {   rad = aptr->irad;
  344.                 if( (aptr->x-rad>=XRange) || 
  345.                     (aptr->x+rad<0) || (aptr->y+rad<0) )
  346.                     continue;
  347.                 if( (scan=aptr->y-rad) > BuckY ) continue;
  348.  
  349.                 if( scan>0 )
  350.                 {   aptr->bucket = YBucket[scan];
  351.                     YBucket[scan] = aptr;
  352.                 } else
  353.                 {   aptr->bucket = *YBucket;
  354.                     *YBucket = aptr;
  355.                 }
  356.             }
  357.     } else
  358.         ForEachAtom
  359.             if( aptr->flag&SphereFlag )
  360.             {   scan = aptr->y-aptr->irad;
  361.                 aptr->bucket = YBucket[scan];
  362.                 YBucket[scan] = aptr;
  363.             }
  364.     BucketFlag = True;
  365. }
  366.  
  367. #if defined(__STDC__) || defined(IBMPC)
  368. /* Function Prototypes */
  369. static void SqrInterval( Interval __far* );
  370. static void VoxelInsert( Atom __far*, int );
  371. static int AtomInter( Atom __far* );
  372. #endif
  373.  
  374.  
  375. static void SqrInterval( ival )
  376.     Interval __far *ival;
  377. {   register Real l,h;
  378.  
  379.     l = ival->l;
  380.     h = ival->h;
  381.  
  382.     if( l>=0.0 )
  383.     {   ival->l = l*l;
  384.         ival->h = h*h;
  385.     } else if( h<0.0 )
  386.     {   ival->l = h*h;
  387.         ival->h = l*l;
  388.     } else
  389.     {   ival->h = (-l>h)? l*l : h*h;
  390.         ival->l = 0.0;
  391.     }
  392. }
  393.  
  394. static void VoxelInsert( ptr, ref )
  395.     Atom __far *ptr;
  396.     int ref;
  397. {
  398.     register int i;
  399.     register Item __far *datum;
  400.  
  401.     if( !FreeItem )
  402.     {   datum = (Item __far*)_fmalloc( PoolSize*sizeof(Item) );
  403.         if( !datum ) FatalRenderError("voxel item");
  404.         for( i=1; i<PoolSize; i++ )
  405.         {   datum->list = FreeItem;
  406.             FreeItem = datum++;
  407.         }
  408.     } else
  409.     {   datum = FreeItem;
  410.         FreeItem = datum->list;
  411.     }
  412.     datum->data = ptr;
  413.     InVoxCount++;
  414.  
  415.     if( !HashTable[ref] ) VoxelCount++;
  416.     datum->list = (Item __far*)HashTable[ref];
  417.     HashTable[ref] = (void __far*)datum;
  418. }
  419.  
  420.  
  421. void ResetVoxelData()
  422. {
  423.     register Item __far *datum;
  424.     register int i;
  425.  
  426.     if( VoxelsDone )
  427.     {   for( i=0; i<VOXSIZE; i++ )
  428.             if( datum = (Item __far*)HashTable[i] )
  429.             {   while( datum->list ) datum = datum->list;
  430.                 datum->list = FreeItem;
  431.                 FreeItem = (Item __far*)HashTable[i];
  432.                 HashTable[i] = (void __far*)0;
  433.             }
  434.         VoxelsDone = False;
  435.     } else for( i=0; i<VOXSIZE; i++ )
  436.         HashTable[i] = (void __far*)0;
  437.     VoxelsClean = True;
  438. }
  439.  
  440.  
  441. void CreateVoxelData()
  442. {
  443.     static Interval ix, iy, iz;
  444.     register int lvx, lvy, lvz;
  445.     register int hvx, hvy, hvz;
  446.     register Long mx, my, mz;
  447.     register int px, py, pz;
  448.     register int i, rad;
  449.     register Real rad2;
  450.  
  451.     register Chain __far *chain;
  452.     register Group __far *group;
  453.     register Atom __far *aptr;
  454.  
  455.  
  456.     ResetVoxelData();
  457.     ProbeCount = InVoxCount = VoxelCount = 0;
  458.     VoxRatio = (Real)SideLen/VOXORDER;
  459.     IVoxRatio = 1.0/VoxRatio;
  460.     VoxelsDone = True;
  461.  
  462.     ForEachAtom
  463.     if( aptr->flag&SphereFlag )
  464.     {   mx = aptr->xorg+Offset;
  465.         my = aptr->yorg+Offset;
  466.         mz = aptr->zorg+Offset;
  467.         rad = aptr->radius;  
  468.         rad2 = (Long)rad*rad;
  469.  
  470.         lvx = (int)((mx-rad)*IVoxRatio);  hvx = (int)((mx+rad)*IVoxRatio);
  471.         lvy = (int)((my-rad)*IVoxRatio);  hvy = (int)((my+rad)*IVoxRatio);
  472.         lvz = (int)((mz-rad)*IVoxRatio);  hvz = (int)((mz+rad)*IVoxRatio);
  473.  
  474.  
  475.         for( px=lvx; px<=hvx; px++ )
  476.         {   ix.l=px*VoxRatio-mx;
  477.             ix.h=ix.l+VoxRatio;  
  478.             SqrInterval(&ix);
  479.             i = VOXORDER2*px + VOXORDER*lvy;
  480.        
  481.             for( py=lvy; py<=hvy; py++ )
  482.             {   iy.l=py*VoxRatio-my;
  483.                 iy.h=iy.l+VoxRatio;
  484.                 SqrInterval(&iy);
  485.                 
  486.                 for( pz=lvz; pz<=hvz; pz++ )
  487.                 {   iz.l=pz*VoxRatio-mz; 
  488.                     iz.h=iz.l+VoxRatio;
  489.                     SqrInterval(&iz);
  490.  
  491.                     if( ((ix.h+iy.h+iz.h)>rad2) && ((ix.l+iy.l+iz.l)<rad2) )
  492.                         VoxelInsert( aptr, i+pz );
  493.                 } /*pz*/
  494.                 i += VOXORDER;
  495.         } /*py*/
  496.         } /*px*/
  497.     }
  498. }
  499.  
  500.  
  501. void ShadowTransform()
  502. {
  503.     ShadowI = OneOverRootSix*(DirX[0]-DirX[1]+DirX[2]+DirX[2]);
  504.     ShadowK = OneOverRootSix*(DirZ[0]-DirZ[1]+DirZ[2]+DirZ[2]);
  505. #ifdef INVERT
  506.     ShadowJ = -OneOverRootSix*(DirY[0]-DirY[1]+DirY[2]+DirY[2]);
  507. #else
  508.     ShadowJ = OneOverRootSix*(DirY[0]-DirY[1]+DirY[2]+DirY[2]);
  509. #endif
  510.  
  511.     if( ShadowI>ApproxZero )
  512.     {   deltax =  (int)(FUDGEFACTOR/ShadowI); xhash =  VOXORDER2; xflag =  1;
  513.     } else if( ShadowI<-ApproxZero )
  514.     {   deltax = -(int)(FUDGEFACTOR/ShadowI); xhash = -VOXORDER2; xflag = -1;
  515.     } else xflag = 0;
  516.  
  517.     if( ShadowJ>ApproxZero )
  518.     {   deltay =  (int)(FUDGEFACTOR/ShadowJ); yhash =  VOXORDER; yflag =  1;
  519.     } else if( ShadowJ<-ApproxZero )
  520.     {   deltay = -(int)(FUDGEFACTOR/ShadowJ); yhash = -VOXORDER; yflag = -1;
  521.     } else yflag = 0;
  522.  
  523.     if( ShadowK>ApproxZero )
  524.     {   deltaz =  (int)(FUDGEFACTOR/ShadowK); zhash = zflag =  1;
  525.     } else if( ShadowK<-ApproxZero )
  526.     {   deltaz = -(int)(FUDGEFACTOR/ShadowK); zhash = zflag = -1;
  527.     } else zflag = 0;
  528. }
  529.  
  530.  
  531. static int AtomInter( ptr )
  532.     Atom __far *ptr;
  533. {
  534.     register int vx, vy, vz;
  535.     register Long modv,rad2;
  536.     register Real tca;
  537.  
  538.     if( ptr->mbox == RayCount )
  539.         return( False );
  540.     ptr->mbox = RayCount;
  541.  
  542.     vx = (int)ptr->xorg-ShadowX;
  543.     vy = (int)ptr->yorg-ShadowY;
  544.     vz = (int)ptr->zorg-ShadowZ;
  545.  
  546.     tca = vx*ShadowI + vy*ShadowJ + vz*ShadowK;
  547.     if( tca<0.0 ) return( False );
  548.     
  549.     rad2 = ptr->radius+10;  rad2 = rad2*rad2;
  550.     modv = (Long)vx*vx + (Long)vy*vy + (Long)vz*vz - rad2;
  551.     return( modv<tca*tca );
  552. }
  553.  
  554.  
  555. static int ShadowRay()
  556. {
  557.     register Item __far * __far *ident;
  558.     register Item __far *ptr;
  559.     register Real ex, ey, ez;
  560.     register Long dx, dy, dz;
  561.     register int ref;
  562.  
  563.    
  564.     RayCount++;
  565.     if( SBuffer )
  566.     {   if( (SBuffer!=Exclude) && AtomInter(SBuffer) )
  567.             return( True );
  568.         SBuffer = (void __far*)0;
  569.     }
  570.  
  571.     ex = IVoxRatio*(ShadowX+Offset);  xcord = (int)ex;
  572.     ey = IVoxRatio*(ShadowY+Offset);  ycord = (int)ey;
  573.     ez = IVoxRatio*(ShadowZ+Offset);  zcord = (int)ez;
  574.  
  575.     ref = VOXORDER2*xcord+VOXORDER*ycord+zcord;
  576.     ident = (Item __far* __far*)(HashTable+ref);
  577.  
  578.     if( xflag==1 ) 
  579.     {   dx = (Long)(((xcord+1)-ex)*deltax);
  580.     } else if( xflag == -1 )
  581.     {   dx = (Long)((ex-xcord)*deltax); 
  582.     } else dx = INFINITY;
  583.  
  584.     if( yflag==1 ) 
  585.     {   dy = (Long)(((ycord+1)-ey)*deltay);
  586.     } else if( yflag == -1 )
  587.     {   dy = (Long)((ey-ycord)*deltay); 
  588.     } else dy = INFINITY;
  589.  
  590.     if( zflag==1 ) 
  591.     {   dz = (Long)(((zcord+1)-ez)*deltaz);
  592.     } else if( zflag == -1 )
  593.     {   dz = (Long)((ez-zcord)*deltaz); 
  594.     } else dz = INFINITY;
  595.  
  596.     
  597.     while( True )
  598.     {   for( ptr = *ident; ptr; ptr = ptr->list )
  599.             if( (ptr->data!=Exclude) && AtomInter(ptr->data) )
  600.             {   SBuffer = ptr->data;
  601.                 return( True );
  602.             }
  603.  
  604.         if( (dx<=dy) && (dx<=dz) )
  605.         {   xcord += xflag;
  606.             if( (xcord<0) || (xcord>=VOXORDER) ) return( False );
  607.             ident += xhash; dx += deltax;
  608.         } else if( dy<=dz  ) /*(dy<=dx)*/
  609.         {   ycord += yflag;
  610.             if( (ycord<0) || (ycord>=VOXORDER) ) return( False );
  611.             ident += yhash; dy += deltay;
  612.         } else /* (dz<=dx) && (dz<=dy) */
  613.         {   zcord += zflag;
  614.             if( (zcord<0) || (zcord>=VOXORDER) ) return( False );
  615.             ident += zhash; dz += deltaz;
  616.         }
  617.     }
  618. }
  619.  
  620.  
  621.  
  622. #define UpdateScanAcross \
  623.         if( depth>*dptr )   \
  624.         {   *dptr = depth;  \
  625.             iptr[dx] = ptr; \
  626.         } dptr++; dx++;
  627.  
  628.  
  629. /* ScanLine for Shadows! */
  630. static void ScanLine()
  631. {
  632.     static Atom __far *list;
  633.     register Atom __far *ptr;
  634.     register Atom __far * __far *iptr;
  635.     register Atom __far * __far *prev;
  636.     register short __huge *dbase;
  637.     register short __huge *dptr;
  638.     register Pixel __huge *fptr;
  639.     register char __far *tptr;
  640.  
  641.     register int pos,depth,inten;
  642.     register int lastx,wide,scan;
  643.     register int dx,dy,dz;
  644.  
  645.     fptr = FBuffer;
  646.     dbase = DBuffer;
  647.     list = (void __far*)0;  
  648.  
  649.     wide = XRange>>2;  iptr = IBuffer;
  650.     for( pos=0; pos<=wide; pos++ )
  651.     {   *iptr++ = (void __far*)0;  *iptr++ = (void __far*)0;
  652.         *iptr++ = (void __far*)0;  *iptr++ = (void __far*)0;
  653.     }
  654.  
  655.  
  656.     for( scan=0; scan<YRange; scan++ )
  657.     {   for( ptr = YBucket[scan]; ptr; ptr = ptr->bucket )
  658.         {    ptr->next = list; list = ptr; }
  659.  
  660.         prev = &list;
  661.         for( ptr=list; ptr; ptr=ptr->next )
  662.         {   dy = scan - ptr->y;
  663.             wide = LookUp[ptr->irad][AbsFun(dy)];
  664.             lastx = (XRange-1)-ptr->x;
  665.             if( wide<lastx ) lastx=wide;
  666.             dx = - MinFun(wide,ptr->x);
  667.  
  668.             iptr = IBuffer+ptr->x;
  669.             tptr = LookUp[wide];
  670.  
  671.             dptr = dbase+ptr->x+dx;
  672.             while( dx<=lastx )
  673.             {   depth = tptr[AbsFun(dx)]+ptr->z;
  674.                 UpdateScanAcross;
  675.             }
  676.  
  677.             /* Remove completed atoms */
  678.             if( dy == ptr->irad )
  679.             {   *prev = ptr->next;
  680.             } else prev = &ptr->next;
  681.         } /*ptr*/
  682.  
  683.  
  684.         /* Process visible scanline */
  685.         prev = (Atom __far* __far*)IBuffer;
  686.         SBuffer = (void __far*)0;
  687.         dptr = dbase; 
  688.  
  689.         for( pos=0; pos<XRange; pos++ )
  690.         {   if( ptr = *prev )
  691.             {   dz = *dptr-ptr->z;
  692. #ifdef INVERT
  693.                 inten = (dz<<1)+(pos-ptr->x)+(scan-ptr->y);
  694. #else
  695.                 inten = (dz<<1)+(pos-ptr->x)-(scan-ptr->y);
  696. #endif
  697.                 if( inten>0 )
  698.                 {   inten = (int)( (inten*ColConst[ptr->irad])>>ColBits);
  699.                     dz = *dptr-ImageRadius;
  700.                     dy = scan-YOffset;
  701.                     dx = pos-XOffset;
  702.  
  703.                     ShadowX = (int)(dx*InvX[0] + dy*InvX[1] + dz*InvX[2]);
  704.                     ShadowY = (int)(dx*InvY[0] + dy*InvY[1] + dz*InvY[2]);
  705.                     ShadowZ = (int)(dx*InvZ[0] + dy*InvZ[1] + dz*InvZ[2]);
  706.  
  707.                     Exclude = ptr;
  708.                     if( ShadowRay() )
  709.                     {   *fptr = Lut[ptr->col+(inten>>2)];
  710.                     } else *fptr = Lut[ptr->col+inten];
  711.                 } else *fptr = Lut[ptr->col];
  712.                 *prev = (void __far*)0;
  713.             }
  714.             dptr++; fptr++; prev++;
  715.         }
  716.         dbase = dptr;
  717.     } /*scan*/
  718. }
  719.  
  720.  
  721. static void DisplaySpaceFill()
  722. {
  723.     register Chain __far *chain;
  724.     register Group __far *group;
  725.     register Atom __far *aptr;
  726.  
  727.     if( UseShadow )
  728.     {   if( !BucketFlag )
  729.             PrepareYBucket();
  730.         ScanLine();
  731.     } else if( UseClipping )
  732.     {   ForEachAtom
  733.             if( aptr->flag&SphereFlag )
  734.                 ClipSphere(aptr->x,aptr->y,aptr->z,aptr->irad,aptr->col);
  735.     } else 
  736.         ForEachAtom
  737.             if( aptr->flag&SphereFlag )
  738.                 DrawSphere(aptr->x,aptr->y,aptr->z,aptr->irad,aptr->col);
  739. }
  740.  
  741.  
  742. #if defined(__STDC__) || defined(IBMPC)
  743. /* Function Prototype */
  744. static void DisplayHBonds( HBond __far *, int );
  745. #endif
  746.  
  747. static void DisplayHBonds( list, mode )
  748.     HBond __far *list; 
  749.     int mode;
  750. {
  751.     register HBond __far *ptr;
  752.     register Atom __far *s;
  753.     register Atom __far *d;
  754.     register int sc,dc;
  755.  
  756.     for( ptr=list; ptr; ptr=ptr->hnext )
  757.         if( ptr->flag & DrawBondFlag )
  758.         {   if( mode )
  759.             {   s = ptr->srcCA; d = ptr->dstCA;
  760.                 if( !s || !d ) continue;
  761.             } else
  762.             {   d = ptr->src;
  763.                 s = ptr->dst;
  764.             }
  765.  
  766.             if( !ptr->col )
  767.             {   sc = s->col;  dc = d->col;
  768.             } else sc = dc = ptr->col;
  769.             if( ptr->flag & CylinderFlag )
  770.             {   if( ptr->irad>0 )
  771.                 {   ClipCylinder(s->x,s->y,s->z,sc,
  772.                                  d->x,d->y,d->z,dc,ptr->irad);
  773.                 } else ClipTwinLine(s->x,s->y,s->z,d->x,d->y,d->z,sc,dc);
  774.             } else ClipDashVector(s->x,s->y,s->z,d->x,d->y,d->z,sc,dc);
  775.         }
  776. }
  777.  
  778. #if defined(__STDC__) || defined(IBMPC)
  779. /* Function Prototype */
  780. static void DisplayRibbon( Chain __far * );
  781. #endif
  782.  
  783.  
  784. static void CalculateInten( ptr )
  785.     Knot *ptr;
  786. {
  787.     register Real inten;
  788.     register int size;
  789.  
  790.     size = isqrt( (Long)ptr->cx*ptr->cx + 
  791.                   (Long)ptr->cy*ptr->cy + 
  792.                   (Long)ptr->cz*ptr->cz );
  793.  
  794.     if( size )
  795.     {   inten = (Real)(ptr->cx-ptr->cy+ptr->cz+ptr->cz)/(size*RootSix);
  796.         if( ptr->cz < 0 ) inten = -inten;
  797.  
  798.         ptr->inten = (int)(ColourMask*inten);
  799.         if( ptr->inten<0 ) ptr->inten = 0;
  800.     } else ptr->inten = ColourMask;
  801. }
  802.  
  803.  
  804. static void DisplayRibbon( chain )
  805.     Chain  __far *chain;
  806. {
  807.     register Group __far *group;
  808.     register Atom __far *captr;
  809.     register Atom __far *o1ptr;
  810.     register Atom __far *o2ptr;
  811.     register Atom __far *next;
  812.  
  813.     register int prev,wide;
  814.     register int col1,col2;
  815.     register int bx,by,bz;
  816.     register int dx,dy,dz;
  817.     register int size;
  818.  
  819.     static Knot mid1, mid2, mid3;
  820.     static Knot knot1, knot2;
  821.  
  822.     prev = False;  
  823.     group = chain->glist;
  824.     if( IsAmino(group->refno) )
  825.     {   captr = FindGroupAtom(group,1);
  826.     } else captr = FindGroupAtom(group,7);
  827.  
  828.     while( group->gnext )
  829.     {   if( IsAmino(group->gnext->refno) )
  830.         {   next = FindGroupAtom(group->gnext,1);
  831.             o1ptr = FindGroupAtom(group,3);
  832.         } else /* Nucleic Acid */
  833.         {   next = FindGroupAtom(group->gnext,7);
  834.             o1ptr = FindGroupAtom(group->gnext,10);
  835.         }
  836.  
  837.         /* When not to have a control point! */
  838.         if( !next || !captr || !o1ptr || (next->flag&BreakFlag) ||
  839.             !((group->flag|group->gnext->flag)&RibbonFlag) )
  840.         {   group = group->gnext;
  841.             captr = next;
  842.             prev = False;
  843.             continue;
  844.         }
  845.  
  846.         knot2.tx = next->x - captr->x;
  847.         knot2.ty = next->y - captr->y;
  848.         knot2.tz = next->z - captr->z;
  849.  
  850.         if( IsAmino(group->refno) )
  851.         {   bx = o1ptr->x - captr->x;
  852.             by = o1ptr->y - captr->y;
  853.             bz = o1ptr->z - captr->z;
  854.  
  855.         } else if( !FindGroupAtom(group,17) && 
  856.                    (o2ptr=FindGroupAtom(group,8)) )
  857.         {   /* Deoxyribonucleic Acid */
  858.             o2ptr = FindGroupAtom(group,8);
  859.             bx = (o1ptr->x + o2ptr->x)/2 - captr->x;
  860.             by = (o1ptr->y + o2ptr->y)/2 - captr->y;
  861.             bz = (o1ptr->z + o2ptr->z)/2 - captr->z;
  862.  
  863.         } else /* Ribonucleic Acid */
  864.         {   bx = o1ptr->x - captr->x;
  865.             by = o1ptr->y - captr->y;
  866.             bz = o1ptr->z - captr->z;
  867.         }
  868.  
  869.         /* c := a x b */
  870.         knot2.cx = knot2.ty*bz - knot2.tz*by;
  871.         knot2.cy = knot2.tz*bx - knot2.tx*bz;
  872.         knot2.cz = knot2.tx*by - knot2.ty*bx;
  873.  
  874.         knot2.px = (captr->x + next->x)/2;
  875.         knot2.py = (captr->y + next->y)/2;
  876.         knot2.pz = (captr->z + next->z)/2;
  877.  
  878.         if( (group->flag&group->gnext->flag) & HelixFlag )
  879.         {   size = isqrt((Long)knot2.cx*knot2.cx + 
  880.                          (Long)knot2.cy*knot2.cy + 
  881.                          (Long)knot2.cz*knot2.cz);
  882.  
  883.             if( size )
  884.             {   wide = (int)(375*Scale);
  885.  
  886. #ifdef INVERT
  887.                 knot2.px += (int)(((Long)wide*knot2.cx)/size);
  888.                 knot2.py += (int)(((Long)wide*knot2.cy)/size);
  889.                 knot2.pz += (int)(((Long)wide*knot2.cz)/size);
  890. #else
  891.                 knot2.px -= (int)(((Long)wide*knot2.cx)/size);
  892.                 knot2.py -= (int)(((Long)wide*knot2.cy)/size);
  893.                 knot2.pz -= (int)(((Long)wide*knot2.cz)/size);
  894. #endif
  895.             }
  896.         }
  897.  
  898.         /* d := c x a */
  899.         dx = (int)(((Long)knot2.cy*knot2.tz - 
  900.                     (Long)knot2.cz*knot2.ty)/96);
  901.         dy = (int)(((Long)knot2.cz*knot2.tx - 
  902.                     (Long)knot2.cx*knot2.tz)/96);
  903.         dz = (int)(((Long)knot2.cx*knot2.ty - 
  904.                     (Long)knot2.cy*knot2.tx)/96);
  905.  
  906.         /* Average Ribbon Width */
  907.         if( group->flag & RibbonFlag )
  908.         {   if( group->gnext->flag & RibbonFlag )
  909.             {   wide = (group->width+group->gnext->width)>>1;
  910.             } else wide = group->width;
  911.         } else wide = group->gnext->width;
  912.         wide = (int)(wide*Scale);
  913.  
  914.         size = isqrt((Long)dx*dx + (Long)dy*dy + (Long)dz*dz);
  915.  
  916.         if( size )
  917.         {   dx = (int)(((Long)wide*dx)/size);
  918.             dy = (int)(((Long)wide*dy)/size);
  919.             dz = (int)(((Long)wide*dz)/size);
  920.  
  921.             /* Handle Carbonyl Oxygen Flip */
  922.             if( prev && ((knot1.wx*dx + knot1.wy*dy + knot1.wz*dz) < 0) )
  923.             {   knot2.wx = -dx;
  924.                 knot2.wy = -dy;
  925.                 knot2.wz = -dz;
  926.             } else
  927.             {   knot2.wx = dx;
  928.                 knot2.wy = dy;
  929.                 knot2.wz = dz;
  930.             }
  931.         } else
  932.         {   knot2.wx = 0;
  933.             knot2.wy = 0;
  934.             knot2.wz = 0;
  935.         }
  936.  
  937.  
  938.         if( RibbonMode )
  939.             CalculateInten( &knot2 );
  940.         if( !(col2 = group->col) )
  941.             col2 = captr->col;
  942.             
  943.  
  944.         if( prev )
  945.         {   /* Approximate spline segment with straight line! */
  946.             /* StrandRibbon( &knot1, &knot2, col1, col2 );   */
  947.  
  948.             /* Calculate Hermite Spline Points */
  949.             mid1.px = (int)(((Long)54*knot1.px + (Long)9*knot1.tx +
  950.                              (Long)10*knot2.px - (Long)3*knot2.tx)>>6);
  951.             mid1.py = (int)(((Long)54*knot1.py + (Long)9*knot1.ty +
  952.                              (Long)10*knot2.py - (Long)3*knot2.ty)>>6);
  953.             mid1.pz = (int)(((Long)54*knot1.pz + (Long)9*knot1.tz +
  954.                              (Long)10*knot2.pz - (Long)3*knot2.tz)>>6);
  955.  
  956.             mid2.px = (4*knot1.px + knot1.tx + 4*knot2.px - knot2.tx)>>3;
  957.             mid2.py = (4*knot1.py + knot1.ty + 4*knot2.py - knot2.ty)>>3;
  958.             mid2.pz = (4*knot1.pz + knot1.tz + 4*knot2.pz - knot2.tz)>>3;
  959.  
  960.             mid3.px = (int)(((Long)10*knot1.px + (Long)3*knot1.tx +
  961.                              (Long)54*knot2.px - (Long)9*knot2.tx)>>6);
  962.             mid3.py = (int)(((Long)10*knot1.py + (Long)3*knot1.ty +
  963.                              (Long)54*knot2.py - (Long)9*knot2.ty)>>6);
  964.             mid3.pz = (int)(((Long)10*knot1.pz + (Long)3*knot1.tz +
  965.                              (Long)54*knot2.pz - (Long)9*knot2.tz)>>6);
  966.  
  967.             /* Calculate Hermite Spline Widths */
  968.             mid1.wx = (27*knot1.wx + 5*knot2.wx)>>5;
  969.             mid1.wy = (27*knot1.wy + 5*knot2.wy)>>5;
  970.             mid1.wz = (27*knot1.wz + 5*knot2.wz)>>5;
  971.  
  972.             mid2.wx = (knot1.wx + knot2.wx)>>1;
  973.             mid2.wy = (knot1.wy + knot2.wy)>>1;
  974.             mid2.wz = (knot1.wz + knot2.wz)>>1;
  975.  
  976.             mid3.wx = (5*knot1.wx + 27*knot2.wx)>>5;
  977.             mid3.wy = (5*knot1.wy + 27*knot2.wy)>>5;
  978.             mid3.wz = (5*knot1.wz + 27*knot2.wz)>>5;
  979.  
  980.             /* Draw the Spline Segments */
  981.             if( RibbonMode ) /* Solid! */
  982.             {   mid1.cx = (27*knot1.cx + 5*knot2.cx)>>5;
  983.                 mid1.cy = (27*knot1.cy + 5*knot2.cy)>>5;
  984.                 mid1.cz = (27*knot1.cz + 5*knot2.cz)>>5;
  985.                 CalculateInten(&mid1);
  986.  
  987.                 mid2.cx = (knot1.cx + knot2.cx)>>1;
  988.                 mid2.cy = (knot1.cy + knot2.cy)>>1;
  989.                 mid2.cz = (knot1.cz + knot2.cz)>>1;
  990.                 CalculateInten(&mid2);
  991.  
  992.                 mid3.cx = (5*knot1.cx + 27*knot2.cx)>>5;
  993.                 mid3.cy = (5*knot1.cy + 27*knot2.cy)>>5;
  994.                 mid3.cz = (5*knot1.cz + 27*knot2.cz)>>5;
  995.                 CalculateInten(&mid3);
  996.  
  997.                 SolidRibbon( &knot1, &mid1,  col1 );
  998.                 SolidRibbon( &mid1,  &mid2,  col1 );
  999.                 SolidRibbon( &mid2,  &mid3,  col2 );
  1000.                 SolidRibbon( &mid3,  &knot2, col2 );
  1001.                 
  1002.             } else /* Strands! */
  1003.             {   StrandRibbon( &knot1, &mid1,  col1 );
  1004.                 StrandRibbon( &mid1,  &mid2,  col1 );
  1005.                 StrandRibbon( &mid2,  &mid3,  col2 );
  1006.                 StrandRibbon( &mid3,  &knot2, col2 );
  1007.             }
  1008.         } else prev = True;
  1009.  
  1010.         group = group->gnext;
  1011.         captr = next;
  1012.  
  1013.         knot1 = knot2;
  1014.         col1 = col2;
  1015.     }
  1016. }
  1017.  
  1018.  
  1019. static void DisplaySelected()
  1020. {
  1021.     register Atom __far *s, __far *d;
  1022.     register Chain __far *chain;
  1023.     register Group __far *group;
  1024.     register Bond __far *bptr;
  1025.     register Atom __far *aptr;
  1026.     register int irad,sc,dc;
  1027.     register int col;
  1028.  
  1029.     irad = (int)(Scale*20);
  1030.  
  1031.     if( irad>0 )
  1032.     {   ForEachBond
  1033.         {   s = bptr->srcatom;  
  1034.             col = (s->flag&SelectFlag)? 1 : 0;
  1035.             sc = Shade2Colour(col);
  1036.  
  1037.             d = bptr->dstatom;  
  1038.             col = (d->flag&SelectFlag)? 1 : 0;
  1039.             dc = Shade2Colour(col);
  1040.             ClipCylinder(s->x,s->y,s->z,sc,d->x,d->y,d->z,dc,irad);
  1041.         }
  1042.     } else ForEachBond
  1043.         {   s = bptr->srcatom;  
  1044.             col = (s->flag&SelectFlag)? 1 : 0;
  1045.             sc = Shade2Colour(col);
  1046.  
  1047.             d = bptr->dstatom;  
  1048.             col = (d->flag&SelectFlag)? 1 : 0;
  1049.             dc = Shade2Colour(col);
  1050.             ClipTwinLine(s->x,s->y,s->z,d->x,d->y,d->z,sc,dc);
  1051.         }
  1052.  
  1053.  
  1054.     irad = (int)(Scale*50);
  1055.     ForEachAtom
  1056.         if( aptr->flag&NonBondFlag )
  1057.         {   col = Shade2Colour( (aptr->flag&SelectFlag)? 1 : 0 );
  1058.             ClipSphere(aptr->x,aptr->y,aptr->z,irad,col);
  1059.         }
  1060. }
  1061.  
  1062.  
  1063. void DrawFrame()
  1064. {
  1065.     register Chain __far *chain;
  1066.  
  1067.     if( !Database ) 
  1068.         return;
  1069.  
  1070.     ClearBuffers();
  1071.  
  1072.     if( UseSlabPlane )
  1073.     {   SlabValue = (int)(DialValue[7]*ImageRadius)+ImageRadius;
  1074.         SlabInten = (int)(ColourMask*TwoOverRootSix);
  1075.         SliceValue = SlabValue+16;
  1076.         UseClipping = True;
  1077.     } else UseClipping = UseScreenClip;
  1078.  
  1079. #ifdef IBMPC
  1080.     /* Lock Buffers into Memory */
  1081.     FBuffer = (Pixel __huge*)GlobalLock(FBufHandle);
  1082.     DBuffer = (short __huge*)GlobalLock(DBufHandle);
  1083. #endif
  1084.  
  1085.     if( !DisplayMode )
  1086.     {   if( UseShadow && DrawAtoms )
  1087.             if( !VoxelsClean )
  1088.                 CreateVoxelData();
  1089.  
  1090.         if( DrawAtoms ) 
  1091.             DisplaySpaceFill();
  1092.  
  1093.         if( !UseSlabPlane || (SlabMode != SlabSection) )
  1094.         {   if( DrawBonds ) 
  1095.                 DisplayWireFrame();
  1096.  
  1097.             if( DrawRibbon )
  1098.                 for( chain=Database->clist; chain; chain=chain->cnext )
  1099.                     if( chain->glist )
  1100.                         DisplayRibbon( chain );
  1101.  
  1102.             DisplayHBonds( Database->slist, SSBondMode );
  1103.             DisplayHBonds( Database->hlist, HBondMode );
  1104.             DisplayBackBone();
  1105.         }
  1106.     } else DisplaySelected();
  1107.  
  1108. #ifdef IBMPC
  1109.     /* Unlock Buffers */
  1110.     GlobalUnlock(FBufHandle);
  1111.     GlobalUnlock(DBufHandle);
  1112. #endif
  1113.     DBClear = False;
  1114.     FBClear = False;
  1115. }
  1116.  
  1117.  
  1118. /* Identified Atom Info */
  1119. static Long IdentDist;
  1120. static int IdentFound;
  1121. static int IdentDepth;
  1122.  
  1123. #if defined(__STDC__) || defined(IBMPC)
  1124. /* Function Prototype */
  1125. static void TestAtomProximity( Atom __far *, int, int );
  1126. #endif
  1127.  
  1128. static void TestAtomProximity( ptr, xpos, ypos )
  1129.     Atom __far *ptr;
  1130.     int xpos, ypos;
  1131. {
  1132.     register Long dist;
  1133.     register int dx,dy;
  1134.  
  1135.     if( UseSlabPlane && (ptr->z>SlabValue) )
  1136.         return;
  1137.  
  1138.     dx = ptr->x - xpos;
  1139.     dy = ptr->y - ypos;
  1140.  
  1141.     dist = (Long)dx*dx + (Long)dy*dy;
  1142.  
  1143.     if( IdentFound )
  1144.     {   if( dist==IdentDist )
  1145.         {   if( ptr->z<IdentDepth )
  1146.                 return;
  1147.         } else if( dist>IdentDist ) 
  1148.             return;
  1149.     }
  1150.  
  1151.     IdentDepth = ptr->z;
  1152.     IdentFound = True;
  1153.     IdentDist = dist;
  1154.     QAtom = ptr;
  1155. }
  1156.  
  1157. void IdentifyAtom( xpos, ypos )
  1158.     int xpos, ypos;
  1159. {
  1160.     register int rad, wide, dpth;
  1161.     register int new, dx, dy, dz;
  1162.     register Chain __far *chain;
  1163.     register Group __far *group;
  1164.     register HBond __far *hptr;
  1165.     register Atom  __far *aptr;
  1166.     register Bond __far *bptr;
  1167.     register char *str;
  1168.     char buffer[40];
  1169.  
  1170.     /* Reset Search */
  1171.     QChain = (void __far*)0;
  1172.     QGroup = (void __far*)0;
  1173.     QAtom = (void __far*)0;
  1174.     IdentFound = False;
  1175.  
  1176.     if( !DisplayMode )
  1177.     {   if( !UseSlabPlane || (SlabMode != SlabSection) )
  1178.         {   if( DrawBonds )
  1179.                 ForEachBond
  1180.                     if( bptr->flag&DrawBondFlag )
  1181.                     {   TestAtomProximity(bptr->srcatom,xpos,ypos);
  1182.                         TestAtomProximity(bptr->dstatom,xpos,ypos);
  1183.                     }
  1184.  
  1185.             ForEachBack
  1186.                 if( bptr->flag&DrawBondFlag )
  1187.                 {   TestAtomProximity(bptr->srcatom,xpos,ypos);
  1188.                     TestAtomProximity(bptr->dstatom,xpos,ypos);
  1189.                 }
  1190.  
  1191.             for( hptr=Database->hlist; hptr; hptr=hptr->hnext )
  1192.                 if( hptr->flag )
  1193.                 {   if( HBondMode )
  1194.                     {   TestAtomProximity(hptr->srcCA,xpos,ypos);
  1195.                         TestAtomProximity(hptr->dstCA,xpos,ypos);
  1196.                     } else
  1197.                     {   TestAtomProximity(hptr->src,xpos,ypos);
  1198.                         TestAtomProximity(hptr->dst,xpos,ypos);
  1199.                     }
  1200.                 }
  1201.  
  1202.             for( hptr=Database->slist; hptr; hptr=hptr->hnext )
  1203.                 if( hptr->flag )
  1204.                 {   if( HBondMode )
  1205.                     {   TestAtomProximity(hptr->srcCA,xpos,ypos);
  1206.                         TestAtomProximity(hptr->dstCA,xpos,ypos);
  1207.                     } else
  1208.                     {   TestAtomProximity(hptr->src,xpos,ypos);
  1209.                         TestAtomProximity(hptr->dst,xpos,ypos);
  1210.                     }
  1211.                 }
  1212.         }
  1213.  
  1214.         ForEachAtom
  1215.         {   /* Identify bond! */
  1216.             if( aptr == QAtom )
  1217.             {   QChain = chain;
  1218.                 QGroup = group;
  1219.             }
  1220.  
  1221.             if( aptr->flag & SphereFlag )
  1222.             {   dy = AbsFun(aptr->y-ypos);
  1223.                 if( dy>aptr->irad ) continue;
  1224.                 rad = LookUp[aptr->irad][dy];
  1225.                 dx = AbsFun(aptr->x-xpos);
  1226.                 if( dx>rad ) continue;
  1227.  
  1228.                 new = False;
  1229.                 dpth = aptr->z+LookUp[rad][dx];
  1230.                 if( UseSlabPlane && (aptr->z+rad>=SlabValue) )
  1231.                 {   dz = SlabValue-aptr->z;
  1232.                     if( SlabMode && (dz >= -rad) )
  1233.                     {   wide = LookUp[aptr->irad][AbsFun(dz)];
  1234.                         if( (dy<=wide) && (dx<=(int)(LookUp[wide][dy])) )
  1235.                         {   if( SlabMode == SlabFinal )
  1236.                             {   dpth = SliceValue;
  1237.                                 new = True;
  1238.                             } else if( SlabMode == SlabHollow )
  1239.                             {   dpth = aptr->z-LookUp[rad][dx];
  1240.                                 new = !IdentFound || (dpth>IdentDepth);
  1241.                             } else if( SlabMode != SlabHalf )
  1242.                             {   /* SlabClose, SlabSection */
  1243.                                 dpth = dx*dx+dy*dy+dz*dz+SliceValue;
  1244.                                 if( IdentFound )
  1245.                                 {   new = (IdentDepth<SliceValue) 
  1246.                                           || (dpth<IdentDepth);
  1247.                                 } else new=True;
  1248.                             }
  1249.                         } else if( (dz>0) && (SlabMode!=SlabSection) )
  1250.                             new = !IdentFound || (dpth>IdentDepth);
  1251.                     }
  1252.                 } else if( !UseSlabPlane || (SlabMode != SlabSection) )
  1253.                     new = !IdentFound || (dpth>IdentDepth);
  1254.  
  1255.                 if( new )
  1256.                 {   IdentFound = True;
  1257.                     IdentDepth = dpth;
  1258.                     IdentDist = 0;
  1259.  
  1260.                     QChain = chain;
  1261.                     QGroup = group;
  1262.                     QAtom = aptr;
  1263.                 }
  1264.             } 
  1265.         }
  1266.     } else /* Display Mode */
  1267.     {   ForEachAtom
  1268.         {   TestAtomProximity(aptr,xpos,ypos);
  1269.             /* Identify bond! */
  1270.             if( aptr == QAtom )
  1271.             {   QChain = chain;
  1272.                 QGroup = group;
  1273.             }
  1274.         }
  1275.     }
  1276.  
  1277.  
  1278.     if( IdentFound && (IdentDist<50) )
  1279.     {   if( CommandActive )
  1280.             WriteChar('\n');
  1281.         CommandActive = False;
  1282.  
  1283.         WriteString("Atom: ");
  1284.         str = ElemDesc[QAtom->refno];
  1285.         if( str[0]!=' ' )   WriteChar(str[0]);
  1286.         WriteChar(str[1]);  WriteChar(str[2]);
  1287.         if( str[3]!=' ' )   WriteChar(str[3]);
  1288.  
  1289.         sprintf(buffer," %d  ",QAtom->serno);
  1290.         WriteString(buffer);
  1291.  
  1292.         str = Residue[QGroup->refno];
  1293.         if( QAtom->flag&HeteroFlag )
  1294.         {   WriteString("Hetero: ");
  1295.         } else WriteString("Group: ");
  1296.  
  1297.         if( str[0]!=' ' )  WriteChar(str[0]);
  1298.         WriteChar(str[1]); WriteChar(str[2]);
  1299.  
  1300.         sprintf(buffer," %d",QGroup->serno);
  1301.         WriteString(buffer);
  1302.  
  1303.         if( QChain->ident!=' ' )
  1304.         {   WriteString("  Chain: ");
  1305.             WriteChar(QChain->ident);
  1306.         }
  1307.         WriteChar('\n');
  1308.     }
  1309. }
  1310.  
  1311.  
  1312. void ResetRenderer()
  1313. {
  1314.     DrawAtoms = False;  MaxAtomRadius = 0;
  1315.     DrawBonds = False;  MaxBondRadius = 0;
  1316.     DrawRibbon = False;
  1317.  
  1318.     SlabMode = SlabClose;
  1319.     UseSlabPlane = False;
  1320.     UseShadow = False;
  1321.  
  1322.     SSBondMode = False;
  1323.     HBondMode = False;
  1324.     DisplayMode = 0;
  1325.     RibbonMode = 0;
  1326.  
  1327.     DrawBoundBox = False;
  1328.     DrawUnitCell = False;
  1329.     DrawAxes = False;
  1330.  
  1331. }
  1332.  
  1333.  
  1334. void InitialiseRenderer()
  1335. {
  1336.     register char __far *ptr;
  1337.     register int index,rad;
  1338.     register int maxval;
  1339.     register Real rad2;
  1340.  
  1341.     FBuffer = (void __huge*)0;  
  1342.     DBuffer = (void __huge*)0;
  1343.     IBuffer = (void __far*)0;   
  1344.     YBucket = (void __far*)0;
  1345.  
  1346. #ifdef IBMPC
  1347.     /* Allocate tables on FAR heaps */ 
  1348.     Array = (char __far*)_fmalloc(7261*sizeof(char));
  1349.     LookUp = (char __far* __far*)_fmalloc(120*sizeof(char __far*));
  1350.     HashTable = (void __far* __far*)_fmalloc(VOXSIZE*sizeof(void __far*));
  1351.     ColConst = (Card __far*)_fmalloc(120*sizeof(Card));
  1352.     
  1353.     if( !Array || !LookUp || !HashTable || !ColConst )
  1354.         FatalRenderError("tables");    
  1355.  
  1356.     FBufHandle = NULL;
  1357.     DBufHandle = NULL;
  1358. #endif
  1359.  
  1360.     ResetRenderer();
  1361.     ReSizeScreen();
  1362.  
  1363.     ptr = Array;
  1364.     for( rad=0; rad<120; rad++ )
  1365.     {   rad2 = rad*rad;
  1366.         LookUp[rad] = ptr;
  1367.         for( index=0; index<=rad; index++ )
  1368. #ifdef ISQRT 
  1369.             *ptr++ = isqrt( (Card)(rad2-index*index) );
  1370. #else 
  1371.             *ptr++ = sqrt( (double)(rad2-index*index) );
  1372. #endif 
  1373.  
  1374.         maxval = (int)(RootSix*rad)+2;
  1375.         ColConst[rad] = ((Card)ColourDepth<<ColBits)/maxval;
  1376.     }
  1377.  
  1378.     FreeItem = (void __far*)0;
  1379.     VoxelsClean = False;
  1380.     VoxelsDone = False;
  1381.  
  1382.     BucketFlag = False;
  1383.     RayCount = 0;
  1384. }
  1385.